﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

using System.Threading;

namespace InteractiveKidsShow
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Kinect kinectObject;
        Speech speechObject;

        private int currentPartNum = 0;
        private bool isPlaying = false; // still needed?
        SynchronizationContext m_context;

        private static SynchronizationContext syncContext;

        public static SynchronizationContext SyncContext
        {
            get
            {
                return syncContext;
            }
            set
            {
                syncContext = value;
            }
        }

        // video parts list
        List<StoryPart> partsList = new List<StoryPart>();

        /// <summary>
        /// load videos in
        /// </summary>
        public void loadVids()
        {
            try
            {
                // read in from file
                using (StreamReader sr = new StreamReader(@"Final.story"))
                {
                    string line;
                    // while there are still lines in the file
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (line == "(Play)") // if just a plain play type
                        {
                            string vidline = sr.ReadLine();
                            Console.WriteLine("vidline was: " + vidline);
                            partsList.Add(new PlayPart(new Uri(vidline, UriKind.Relative)));
                            Console.WriteLine("PlayPart URI worked");
                        }
                        else if (line == "(Decision)") //otherwise is one of the decision types
                        {
                            string[] decisionvidline = sr.ReadLine().Split(',');
                            string decisionvid = decisionvidline[0];
                            int decisionvidLength = Convert.ToInt32(decisionvidline[1]);
                            string decisionTypeLine = sr.ReadLine();
                            if (decisionTypeLine == "Gesture") // gesture type
                            {
                                string gestureLine = sr.ReadLine();
                                EnumKinectGestures.Gestures gesture = (EnumKinectGestures.Gestures)Enum.Parse(typeof(EnumKinectGestures.Gestures), gestureLine);
                                string ifDoneVidLine = sr.ReadLine();
                                string ifNotVidLine = sr.ReadLine();
                                Console.WriteLine("Gesture vidline was: " + decisionvidline);
                                partsList.Add(new GestureDecisionPart(new Uri(decisionvid, UriKind.Relative), decisionvidLength, gesture, new Uri(ifDoneVidLine, UriKind.Relative), new Uri(ifNotVidLine, UriKind.Relative)));
                                Console.WriteLine("Gesture URI worked");
                            }
                            else if (decisionTypeLine == "Speech") // speech type
                            {
                                
                                string wordLine = sr.ReadLine();
                                //int timerLine = Convert.ToInt16(sr.ReadLine());
                                string ifDoneVidLine = sr.ReadLine();
                                string ifNotVidLine = sr.ReadLine();
                                Console.WriteLine("Speech vidline was: " + decisionvidline);
                                partsList.Add(new SpeechDecisionPart(new Uri(decisionvid, UriKind.Relative), decisionvidLength, wordLine, new Uri(ifDoneVidLine, UriKind.Relative), new Uri(ifNotVidLine, UriKind.Relative)));
                                Console.WriteLine("Speech URI worked");
                            }
                            else if (decisionTypeLine == "Button") // button type
                            {
                                
                                int numButtonsLine = Convert.ToInt16(sr.ReadLine());
                                List<InteractButton> buttons = new List<InteractButton>();
                                for (int i = 0; i < numButtonsLine; i++)
                                {
                                    string buttonLine = sr.ReadLine();
                                    string[] buttonLineParts = buttonLine.Split(',');
                                    buttons.Add(new InteractButton(buttonLineParts[0], Convert.ToInt16(buttonLineParts[1]), Convert.ToInt16(buttonLineParts[2]), Convert.ToInt16(buttonLineParts[3]), Convert.ToInt16(buttonLineParts[4]), new Uri(buttonLineParts[5], UriKind.Relative)));
                                    Console.WriteLine("Button URI worked");
                                }
                                //string temp = sr.ReadLine();
                                //int timerLine = Convert.ToInt16(temp);
                                Console.WriteLine("Button vidline was: " + decisionvidline);
                                partsList.Add(new ButtonDecisionPart(new Uri(decisionvid, UriKind.Relative), decisionvidLength, buttons));
                            }
                            else
                                MessageBox.Show("Invalid input: " + line);
                        }
                        else if (line == "" || line == null)
                        {
                            //sr.ReadLine();
                        }
                        else
                            MessageBox.Show("Invalid input:" + line);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            SyncContext = SynchronizationContext.Current;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            kinectObject = new Kinect();
            kinectObject.Load();

            m_context = SynchronizationContext.Current;
            speechObject = new Speech(m_context);

            kinectObject.HandsMoved += new Kinect.HandsMovedEventHandler(HandsMoved);
            kinectObject.GestureResponse += new Kinect.GestureResponseEventHandler(GestureResponse);
            kinectObject.ButtonResponse += new Kinect.ButtonResponseEventHandler(ButtonResponse);

            speechObject.SpeechResponse += new Speech.SpeechResponseEventHandler(SpeechResponse);

            Thread speechThread = new Thread(new ThreadStart(speechObject.InitAudio));
            speechThread.Start();

            loadVids();
        }

        private void HandsMoved(object sender, HandsMovedArgs args)
        {
            Canvas.SetLeft(leftHandEllipse, args.leftHandEllipse.X);
            Canvas.SetTop(leftHandEllipse, args.leftHandEllipse.Y);

            Canvas.SetLeft(rightHandEllipse, args.rightHandEllipse.X);
            Canvas.SetTop(rightHandEllipse, args.rightHandEllipse.Y);
        }

        private void SpeechResponse(object sender, SpeechResponseArgs args)
        {
            /*SyncContext.Post(
                (o) =>
                {
                    this.Title = args.getWordSaid;
                }
                , null
            );*/

            if (partsList[currentPartNum] is SpeechDecisionPart)
            {
                // acknowledge that the word was said in the part's variable
                (partsList[currentPartNum] as SpeechDecisionPart).wordWasSaid = true;
                // stop playing the current video and move to the next
                mediaPlayer_MediaEnded(this, null);
            }
            else
                MessageBox.Show("Speech response event was called at wrong time?");
        }

        private void GestureResponse(object sender, GestureResponseArgs args)
        {
            //this.Title = "Gesture was done";

            if (partsList[currentPartNum] is GestureDecisionPart)
            {
                // acknowledge that the gesture was done in the part's variable
                (partsList[currentPartNum] as GestureDecisionPart).gestureWasDone = true;
                // stop playing the current video and move to the next
                mediaPlayer_MediaEnded(this, null);
            }
            else
                MessageBox.Show("Gesture response event was called at wrong time?");

        }

        private void ButtonResponse(object sender, ButtonResponseArgs args)
        {
            //this.Title = args.buttonSelected;

            if (partsList[currentPartNum] is ButtonDecisionPart)
            {
                // find the index in the part's array of the button with the same name as the one passed in
                int theButtonChosen = 0;
                for (int i = 0; i < (partsList[currentPartNum] as ButtonDecisionPart).buttons.Count(); i++)
                {
                    if ((partsList[currentPartNum] as ButtonDecisionPart).buttons[i].buttonName == args.buttonSelected)
                    {
                        theButtonChosen = i;
                        break;
                    }
                }
                // store which button was chosen in the part's variable
                (partsList[currentPartNum] as ButtonDecisionPart).buttonChosen = theButtonChosen;
                // stop playing the current video and move to the next
                mediaPlayer_MediaEnded(this, null);
            }
            else
                MessageBox.Show("Button response event was called at wrong time?");

        }

        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            kinectObject.Unload();
            Environment.Exit(0);
        }

        /// <summary>
        /// Plays or pauses the video at its current point, or starts from beginning if it hasn't started yet.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonPlay_Click(object sender, RoutedEventArgs e)
        {
            if (!isPlaying) // if is not playing
            {
                Console.WriteLine("not playing");
                // play the current part
                if (partsList[currentPartNum] is PlayPart)
                {
                    Console.WriteLine("currentPartNum: " + currentPartNum);
                    PlayPart thePart = partsList[currentPartNum] as PlayPart;
                    thePart.Play(ref mediaPlayer);
                    Console.WriteLine("passed play method for playpart");
                }
                else if (partsList[currentPartNum] is GestureDecisionPart)
                {
                    GestureDecisionPart thePart = partsList[currentPartNum] as GestureDecisionPart;
                    thePart.Play(ref mediaPlayer, ref kinectObject);
                }
                else if (partsList[currentPartNum] is SpeechDecisionPart)
                {
                    SpeechDecisionPart thePart = partsList[currentPartNum] as SpeechDecisionPart;
                    thePart.Play(ref mediaPlayer, ref speechObject);
                }
                else // otherwise is a ButtonDecisionPart
                {
                    ButtonDecisionPart thePart = partsList[currentPartNum] as ButtonDecisionPart;
                    thePart.Play(ref mediaPlayer, ref kinectObject);
                }

                buttonPlay.Content = "Pause";


                
            }
            else // otherwise is already playing
            {
                mediaPlayer.Pause();
                buttonPlay.Content = "Play";
                // should there be more here? will just this work?
            }
            isPlaying = !isPlaying;
        }

        /// <summary>
        /// Stops the video and sets it back to the state at beginning of the story.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonStop_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
            // starts everything from the beginning of the whole list
            currentPartNum = 0;
            foreach (StoryPart aPart in partsList)
            {
                if (aPart is PlayPart)
                {
                    PlayPart thePart = aPart as PlayPart;
                    thePart.hasVidPlayed = false;
                }
                else
                {
                    if (partsList[currentPartNum] is SpeechDecisionPart)
                    {
                        SpeechDecisionPart thePart = partsList[currentPartNum] as SpeechDecisionPart;
                        if (thePart == null)
                            MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                        thePart.hasVidPlayed = false;
                        thePart.hasSecondVidPlayed = false;
                    }
                    else if (partsList[currentPartNum] is GestureDecisionPart)
                    {
                        GestureDecisionPart thePart = partsList[currentPartNum] as GestureDecisionPart;
                        if (thePart == null)
                            MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                        thePart.hasVidPlayed = false;
                        thePart.hasSecondVidPlayed = false;
                    }
                    else // otherwise is a button part
                    {
                        ButtonDecisionPart thePart = partsList[currentPartNum] as ButtonDecisionPart;
                        if (thePart == null)
                            MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                        thePart.hasVidPlayed = false;
                        thePart.hasSecondVidPlayed = false;
                    }
                }
                mediaPlayer.Stop();
                mediaPlayer.Source = null;
                isPlaying = false;
                buttonPlay.Content = "Play";
            }
        }

        private void buttonTiltUp_Click(object sender, RoutedEventArgs e)
        {
            kinectObject.TiltUp();
        }

        private void buttonTiltDown_Click(object sender, RoutedEventArgs e)
        {
            kinectObject.TiltDown();
        }

        
        /// <summary>
        /// Plays the next video whenever a video ends, by determining first if it should move on to the next part, repeat the request vid,
        /// or play one of the confirmation/branching vids. Does nothing if we've gotten to the end of the story.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mediaPlayer_MediaEnded(object sender, RoutedEventArgs e)
        {

            if (partsList[currentPartNum] is PlayPart)
            {
                if (currentPartNum + 1 >= partsList.Count())
                    return;
                else
                {
                    moveToNextPartAndPlay();
                }
            }
            else
            {
                if (partsList[currentPartNum] is SpeechDecisionPart) // if is a speech part ====================================
                {
                    SpeechDecisionPart thePart = partsList[currentPartNum] as SpeechDecisionPart;
                    if (thePart == null)
                        MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                    if (!thePart.hasSecondVidPlayed) // if the second vid hasn't played, call play again
                    {
                        thePart.Play(ref mediaPlayer, ref speechObject);
                    }
                    else // otherwise move on to the next part
                    {
                        if (currentPartNum + 1 >= partsList.Count())
                            return;
                        else
                        {
                            moveToNextPartAndPlay();                          
                        }
                    }
                }
                else if (partsList[currentPartNum] is GestureDecisionPart) // if is a gesture part ====================================
                {
                    GestureDecisionPart thePart = partsList[currentPartNum] as GestureDecisionPart;
                    if (thePart == null)
                        MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                    if (!thePart.hasSecondVidPlayed) // if the second vid hasn't played, call play again
                    {
                        thePart.Play(ref mediaPlayer, ref kinectObject);
                    }
                    else // otherwise move on to the next part
                    {
                        if (currentPartNum + 1 >= partsList.Count())
                            return;
                        else
                        {
                            moveToNextPartAndPlay();
                        }
                    }
                }
                else // otherwise is a button part ==========================================================
                {
                    ButtonDecisionPart thePart = partsList[currentPartNum] as ButtonDecisionPart;
                    if (thePart == null)
                        MessageBox.Show("Your as keyword thing didn't work."); // testing; take it out later

                    if (!thePart.hasSecondVidPlayed) // if the second vid hasn't played, call play again
                    {
                        thePart.Play(ref mediaPlayer, ref kinectObject);
                    }
                    else // otherwise move on to the next part
                    {
                        if (currentPartNum + 1 >= partsList.Count())
                            return;
                        else
                        {
                            moveToNextPartAndPlay();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Should only be called from the mediaEnded event, I think?
        /// </summary>
        private void moveToNextPartAndPlay()
        {
            currentPartNum++;
            if (partsList[currentPartNum] is PlayPart)
            {
                
                PlayPart thePart = partsList[currentPartNum] as PlayPart;
                thePart.Play(ref mediaPlayer);
            }
            else if (partsList[currentPartNum] is GestureDecisionPart)
            {
                GestureDecisionPart thePart = partsList[currentPartNum] as GestureDecisionPart;
                thePart.Play(ref mediaPlayer, ref kinectObject);
            }
            else if (partsList[currentPartNum] is SpeechDecisionPart)
            {
                SpeechDecisionPart thePart = partsList[currentPartNum] as SpeechDecisionPart;
                thePart.Play(ref mediaPlayer, ref speechObject);
            }
            else // otherwise is a ButtonDecisionPart
            {
                ButtonDecisionPart thePart = partsList[currentPartNum] as ButtonDecisionPart;
                thePart.Play(ref mediaPlayer, ref kinectObject);
            }
        
        }

        private void buttonDoTheThing_Click(object sender, RoutedEventArgs e)
        {
            // use for testing without kinect - maybe make 3? more?
        }

    }
}
